﻿using SuperX.SuperSocket.Common;
using System;
using System.IO;
using System.Text;
using System.Threading;

namespace SuperX.SuperSocket.Server
{
    public class UpLoadEngine : IDisposable
    {
        private AutoResetEvent m_EndEvent = new AutoResetEvent(false);
        private FileStream m_fileStream;
        private int TransferStatus = 0;

        //0:初始化状态，1：CheckFile,3,OnUpLoad,开始上传，4，OnDoData，数据接受中，5，数据接受完成,6,已结束的标志
        public long TransferedLength = 0L;

        private IOTSocketSession TransferSession;
        public UpLoadInfo UpLoadInfo;
        private Thread thread;

        public delegate void TransferStepEventHandler(TransferStepEventArgs e);

        public event TransferStepEventHandler TransferStep;

        public delegate void TransferCompleteEventHandler(EventArgs e, UpLoadEngine s);

        public event TransferCompleteEventHandler TransferComplete;

        public delegate void StartTransferEventHandler(StartTransferEventArgs e);

        public event StartTransferEventHandler StartTransfer;

        public UpLoadEngine(IOTSocketSession _TransferSession)
        {
            TransferStatus = 0;
            TransferSession = _TransferSession;
        }

        public void Dispose()
        {
            if (m_fileStream != null)
            {
                m_fileStream.Close();
                m_fileStream = null;
            }
            if (TransferSession != null)
            {
                TransferSession.Close();
                TransferSession = null;
            }
            if (thread != null)
            {
                if (thread.IsAlive)
                    thread.Abort();
                thread = null;
            }
            UpLoadInfo = null;
            TransferedLength = 0L;
        }

        internal void OnCheckFile(Tag opCode, bool IsFileExist)
        {
            TransferStatus = 1;
            string s = IsFileExist ? "1" : "0";
            byte[] bytes = Encoding.UTF8.GetBytes(s);
            SendData(opCode, bytes, 0, bytes.Length);
        }

        public void OnDoData(byte[] data, int offset, int count)
        {
            TransferStatus = 4;
            m_fileStream.Write(data, offset, count);
            TransferedLength += count;
            OnTransferStep(UpLoadInfo.TransferLength, TransferedLength, count);
            if (TransferedLength >= UpLoadInfo.TransferLength)
            {
                TransferStatus = 5;
                thread = new Thread(new ThreadStart(() =>
                {
                    if (!m_EndEvent.WaitOne(5000))
                    {
                        if (TransferStatus < 6)
                        {
                            DoEnd();
                        }
                    }
                }));
                thread.IsBackground = true;
                thread.Start();
            }
        }

        internal void OnTransferStep(long _TotalLen, long _TransferLen, int _CurrentPacket)
        {
            if (TransferStep != null)
            {
                TransferStep(new TransferStepEventArgs(_TotalLen, _TransferLen, _CurrentPacket));
            }
        }

        public void DoEnd()
        {
            if (TransferComplete != null)
                TransferComplete(new EventArgs(), this);
            TransferSession.Close();
            Dispose();//关闭文件流
            TransferStatus = 6;
        }

        public void OnDoEnd()
        {
            DoEnd();
        }

        internal void OnUpLoad(UpLoadInfo uploadInfo)
        {
            TransferStatus = 3;
            UpLoadInfo = uploadInfo;
            if (StartTransfer != null) StartTransfer(new StartTransferEventArgs(uploadInfo));
            string fullPath = Path.GetFullPath(uploadInfo.SaveName);
            string dirPath = Path.GetDirectoryName(fullPath);
            if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
            m_fileStream = new FileStream(fullPath, FileMode.OpenOrCreate, FileAccess.Write);
            m_fileStream.SetLength(uploadInfo.FileSize);
            SendData(Tag.DoData, new byte[] { 1 }, 0, 1);
        }

        internal void SendData(Tag opCode, byte[] data, int offset, int length)
        {
            byte[] dst = new byte[length + 4];
            dst[0] = (byte)((int)opCode / 256);
            dst[1] = (byte)((int)opCode % 256);
            dst[2] = (byte)(data.Length / 256);
            dst[3] = (byte)(data.Length % 256);
            Buffer.BlockCopy(data, offset, dst, 4, length);
            TransferSession.Send(dst, 0, dst.Length);
        }
    }

    public class StartTransferEventArgs
    {
        public UpLoadInfo UpLoadInfo { get; set; }

        public StartTransferEventArgs(UpLoadInfo _UpLoadInfo)
        {
            UpLoadInfo = _UpLoadInfo;
        }
    }

    public class TransferStepEventArgs
    {
        public TransferStepEventArgs(long _TotalLen, long _TransferLen, int _CurrentPacket)
        {
            TotalLen = _TotalLen;
            TransferLen = _TransferLen;
            CurrentPacket = _CurrentPacket;
        }

        public int CurrentPacket { get; set; }

        public long TotalLen { get; set; }

        public long TransferLen { get; set; }
    }
}